"""
OpenAI API 服务 (services/openai_service.py)

提供与 OpenAI API 交互的功能，包括图片识别和标签生成。
"""
import os
import requests
import base64
import logging
import json
import re
from config.config import APP_CONFIG

logger = logging.getLogger(__name__)

# OpenAI API 配置
OPENAI_CONFIG = APP_CONFIG.get('OPENAI_API', {})
OPENAI_API_KEY = OPENAI_CONFIG.get('API_KEY') or os.environ.get('OPENAI_API_KEY')
OPENAI_MODEL = OPENAI_CONFIG.get('MODEL', 'gpt-4o-mini')
OPENAI_MAX_TOKENS = OPENAI_CONFIG.get('MAX_TOKENS', 300)
OPENAI_API_URL = "https://api.openai.com/v1/chat/completions"

# Ollama配置
OLLAMA_CONFIG = APP_CONFIG.get('OLLAMA_API', {})
USE_OLLAMA = OLLAMA_CONFIG.get('USE_OLLAMA', False)

def fix_json_format(json_str):
    """
    修复常见的JSON格式问题
    
    Args:
        json_str: 可能格式不正确的JSON字符串
        
    Returns:
        str: 修复后的JSON字符串
    """
    # 将单引号替换为双引号
    fixed_str = json_str.replace("'", '"')
    # 修复缺少双引号的键名
    fixed_str = re.sub(r'([{,])\s*([a-zA-Z0-9_]+):', r'\1"\2":', fixed_str)
    return fixed_str

def extract_tags_from_text(text):
    """
    从文本中尝试提取标签，多种方法尝试解析
    
    Args:
        text: 包含JSON或标签的文本
        
    Returns:
        dict: 包含'cn_tags'的字典，或空字典
    """
    # 先尝试找到并解析JSON对象
    json_pattern = r'\{.*?\}'
    match = re.search(json_pattern, text, re.DOTALL)
    
    if match:
        json_str = match.group(0)
        try:
            # 尝试直接解析
            data = json.loads(json_str)
            if 'cn_tags' in data:
                return data
        except json.JSONDecodeError:
            # 尝试修复后解析
            try:
                fixed_json = fix_json_format(json_str)
                data = json.loads(fixed_json)
                if 'cn_tags' in data:
                    return data
            except json.JSONDecodeError:
                pass
    
    # 尝试解析标签数组
    array_pattern = r'\[\s*"[^"]*"(?:\s*,\s*"[^"]*")*\s*\]'
    match = re.search(array_pattern, text.replace("'", '"'), re.DOTALL)
    if match:
        try:
            tags = json.loads(match.group(0))
            return {"cn_tags": tags}
        except json.JSONDecodeError:
            pass
    
    # 尝试从文本中提取引号包围的字符串
    tags = re.findall(r'["\'](.*?)["\']', text)
    if tags:
        # 过滤掉非标签内容
        filtered_tags = [tag for tag in tags if len(tag) > 1 and not any(kw in tag.lower() for kw in ['cn_tags', 'tags', 'tag'])]
        if filtered_tags:
            return {"cn_tags": filtered_tags[:5]}  # 最多取5个标签
    
    # 所有方法都失败，返回空对象
    return {}

def analyze_image(image_path):
    """
    使用 OpenAI API 分析图片并生成中英文标签。

    Args:
        image_path: 图片文件的完整路径

    Returns:
        tuple: (
            {
                'cn_tags': [中文标签列表]
            },
            None
        ) 或 (None, 错误信息)
    """
    if not OPENAI_API_KEY:
        logger.error("OpenAI API 密钥未配置。请设置环境变量 OPENAI_API_KEY")
        return None, "OpenAI API 密钥未配置"

    if not os.path.exists(image_path):
        logger.error(f"图片文件不存在: {image_path}")
        return None, f"图片文件不存在: {image_path}"

    try:
        # 读取并编码图片为 base64
        with open(image_path, "rb") as image_file:
            base64_image = base64.b64encode(image_file.read()).decode('utf-8')

        # 构建 API 请求
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {OPENAI_API_KEY}"
        }

        # 使用 gpt-4o-mini 模型进行图片分析
        # 明确要求返回标准JSON格式
        prompt = """分析这张图片，从表情，情感，事物，场景维度进行分析。
给出5个最相关的中文标签。

请严格使用以下JSON格式返回，务必使用双引号而非单引号：
{"cn_tags": ["标签1", "标签2", "标签3", "标签4", "标签5"]}

不要返回任何其它说明文字，只返回上面的JSON格式数据。"""

        payload = {
            "model": OPENAI_MODEL,
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": prompt
                        },
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/jpeg;base64,{base64_image}"
                            }
                        }
                    ]
                }
            ],
            "max_tokens": OPENAI_MAX_TOKENS
        }

        # 发送请求
        response = requests.post(OPENAI_API_URL, headers=headers, json=payload)
        response.raise_for_status()

        # 解析响应
        result = response.json()
        content = result['choices'][0]['message']['content']
        
        logger.debug(f"OpenAI返回原始内容: {content}")

        # 使用增强的提取方法
        tags_data = extract_tags_from_text(content)
        
        if tags_data and 'cn_tags' in tags_data:
            return tags_data, None
        
        # 如果正常解析失败，记录错误并返回
        logger.error(f"无法从API响应中提取有效标签: {content}")
        return None, "无法从API响应中提取有效标签"

    except requests.exceptions.RequestException as e:
        logger.error(f"OpenAI API 请求失败: {str(e)}")
        return None, f"OpenAI API 请求失败: {str(e)}"
    except Exception as e:
        logger.error(f"图片分析过程中出错: {str(e)}")
        return None, f"图片分析过程中出错: {str(e)}"

def get_image_tags(image_path):
    """
    分析图片并返回标签，便于业务层调用。
    根据配置选择使用OpenAI或Ollama进行图片分析。

    Args:
        image_path: 图片文件路径

    Returns:
        dict: {'cn_tags': [...]} 或空字典 {}
    """
    if USE_OLLAMA:
        logger.info("使用Ollama的deepseek-vision模型进行图片分析")
        try:
            from services.ollama_service import analyze_image_with_ollama
            tags_data, error = analyze_image_with_ollama(image_path)

            # 如果Ollama分析失败但错误与服务可用性相关，尝试回退到OpenAI
            if error and ("无法连接到Ollama服务" in error or "模型不存在" in error):
                logger.warning(f"Ollama服务不可用: {error}，尝试回退到OpenAI")
                # 检查OpenAI是否可用
                if OPENAI_API_KEY:
                    logger.info("回退到OpenAI进行图片分析")
                    tags_data, openai_error = analyze_image(image_path)
                    if openai_error:
                        logger.error(f"OpenAI回退也失败: {openai_error}")
                        return {}
                    return tags_data
                else:
                    logger.error("无法回退到OpenAI: API密钥未配置")
                    return {}
        except ImportError:
            logger.error("Ollama服务模块不可用，回退到OpenAI")
            tags_data, error = analyze_image(image_path)
    else:
        logger.info("使用OpenAI进行图片分析")
        tags_data, error = analyze_image(image_path)

    if error:
        logger.warning(f"获取图片标签失败: {error}")
        return {}
        
    # 验证返回结果格式
    if isinstance(tags_data, dict) and 'cn_tags' in tags_data:
        return tags_data
    elif isinstance(tags_data, list):
        # 兼容直接返回标签列表的情况
        return {'cn_tags': tags_data}
    else:
        logger.warning(f"标签数据格式不符合预期: {tags_data}")
        return {}
